Tutustu TypeScript enum -vaihtoehtoihin, kuten const assertions ja union types, ja opi milloin niitä käytetään koodin ylläpidettävyyden ja suorituskyvyn optimoimiseksi.
TypeScript Enum -vaihtoehdot: Const Assertions vs. Union Types
TypeScriptin enum on tehokas ominaisuus nimettyjen vakioiden määrittämiseen. Se ei kuitenkaan ole aina paras valinta. Tämä artikkeli tutkii enumien vaihtoehtoja, erityisesti const assertions ja union types, ja antaa ohjeita siitä, milloin niitä käytetään koodin laadun, ylläpidettävyyden ja suorituskyvyn optimoimiseksi. Perehdymme kunkin lähestymistavan vivahteisiin tarjoten käytännön esimerkkejä ja käsittelemme yleisiä huolenaiheita.
TypeScript Enumien Ymmärtäminen
Ennen kuin sukellamme vaihtoehtoihin, katsotaan nopeasti läpi TypeScript enumit. Enum on tapa määrittää joukko nimettyjä numeerisia vakioita. Oletuksena ensimmäiselle enumin jäsenelle annetaan arvo 0, ja seuraavia jäseniä kasvatetaan yhdellä.
enum Status {
Pending,
InProgress,
Completed,
Rejected,
}
const currentStatus: Status = Status.InProgress; // currentStatus will be 1
Voit myös eksplisiittisesti määrittää arvot enumin jäsenille:
enum HTTPStatus {
OK = 200,
BadRequest = 400,
Unauthorized = 401,
Forbidden = 403,
NotFound = 404,
}
const serverResponse: HTTPStatus = HTTPStatus.OK; // serverResponse will be 200
Enumien Hyödyt
- Luettavuus: Enumit parantavat koodin luettavuutta tarjoamalla mielekkäitä nimiä numeerisille vakioille.
- Tyyppiturvallisuus: Ne takaavat tyyppiturvallisuuden rajoittamalla arvot määritettyihin enumin jäseniin.
- Automaattinen täydennys: IDE:t tarjoavat automaattisia täydennysehdotuksia enumin jäsenille, mikä vähentää virheitä.
Enumien Haitat
- Suoritusaikainen lisäkuorma: Enumit käännetään JavaScript-objekteiksi, mikä voi aiheuttaa suoritusaikaista lisäkuormaa, erityisesti suurissa sovelluksissa.
- Muunneltavuus: Enumit ovat oletusarvoisesti muunneltavissa. Vaikka TypeScript tarjoaa
const enum-ominaisuuden muuntamisen estämiseksi, sillä on rajoituksia. - Käänteinen Mäppäys: Numeeriset enumit luovat käänteisen mäppäyksen (esim.
Status[1]palauttaa "InProgress"), mikä on usein tarpeetonta ja voi lisätä paketin kokoa.
Vaihtoehto 1: Const Assertions
Const assertions tarjoavat tavan luoda muuttumattomia, vain luku -datarakenteita. Niitä voidaan käyttää vaihtoehtona enumille monissa tapauksissa, erityisesti kun tarvitset yksinkertaisen joukon merkkijono- tai numeerisia vakioita.
const Status = {
Pending: 'pending',
InProgress: 'in_progress',
Completed: 'completed',
Rejected: 'rejected',
} as const;
// Typescript infers the following type:
// {
// readonly Pending: "pending";
// readonly InProgress: "in_progress";
// readonly Completed: "completed";
// readonly Rejected: "rejected";
// }
type StatusType = typeof Status[keyof typeof Status]; // 'pending' | 'in_progress' | 'completed' | 'rejected'
function processStatus(status: StatusType) {
console.log(`Processing status: ${status}`);
}
processStatus(Status.InProgress); // Valid
// processStatus('invalid'); // Error: Argument of type '"invalid"' is not assignable to parameter of type 'StatusType'.
Tässä esimerkissä määritämme tavallisen JavaScript-objektin, jolla on merkkijonoarvoja. as const -assertion kertoo TypeScriptille, että tätä objektia on käsiteltävä vain luku -tilassa ja sen ominaisuuksille on pääteltävä tarkimmat mahdolliset tyypit. Sitten poimimme avaimista union-tyypin. Tämä lähestymistapa tarjoaa useita etuja:
Const Assertions -ominaisuuden hyödyt
- Muuttumattomuus: Const assertions luovat muuttumattomia datarakenteita, jotka estävät tahattomat muutokset.
- Ei suoritusaikaista lisäkuormaa: Ne ovat yksinkertaisia JavaScript-objekteja, joten enumeihin ei liity suoritusaikaista lisäkuormaa.
- Tyyppiturvallisuus: Ne tarjoavat vahvan tyyppiturvallisuuden rajoittamalla arvot määritettyihin vakioihin.
- Tree-shaking ystävällinen: Modernit bundlerit voivat helposti poistaa käyttämättömät arvot (tree-shake), mikä pienentää paketin kokoa.
Huomioitavaa Const Assertions -ominaisuuden kanssa
- Monisanaisempi: Määrittely ja tyypitys voi olla hieman monisanaisempaa kuin enumit, erityisesti yksinkertaisissa tapauksissa.
- Ei käänteistä mäppäystä: Ne eivät tarjoa käänteistä mäppäystä, mutta tämä on usein etu eikä haitta.
Vaihtoehto 2: Union Types
Union types -tyyppien avulla voit määrittää muuttujan, joka voi sisältää yhden useista mahdollisista tyypeistä. Ne ovat suorempi tapa määrittää sallitut arvot ilman objektia, mikä on hyödyllistä, kun et tarvitse enumin tai const assertion:in avain-arvo-suhdetta.
type Status = 'pending' | 'in_progress' | 'completed' | 'rejected';
function processStatus(status: Status) {
console.log(`Processing status: ${status}`);
}
processStatus('in_progress'); // Valid
// processStatus('invalid'); // Error: Argument of type '"invalid"' is not assignable to parameter of type 'Status'.
Tämä on ytimekäs ja tyyppiturvallinen tapa määrittää joukko sallittuja arvoja.
Union Types -tyyppien hyödyt
- Ytimekkyys: Union types -tyypit ovat ytimekkäin lähestymistapa, erityisesti yksinkertaisille merkkijono- tai numeeristen vakioiden joukoille.
- Tyyppiturvallisuus: Ne tarjoavat vahvan tyyppiturvallisuuden rajoittamalla arvot määritettyihin vaihtoehtoihin.
- Ei suoritusaikaista lisäkuormaa: Union types -tyypit ovat olemassa vain käännösaikana, eikä niillä ole suoritusaikaista esitystä.
Huomioitavaa Union Types -tyyppien kanssa
- Ei avain-arvo-assosiaatiota: Ne eivät tarjoa avain-arvo-suhdetta, kuten enumit tai const assertions. Tämä tarkoittaa, että et voi helposti etsiä arvoa sen nimen perusteella.
- Merkkijonoliteraalien toisto: Saatat joutua toistamaan merkkijonoliteraaleja, jos käytät samaa arvojoukkoa useissa paikoissa. Tätä voidaan lieventää jaetulla
type-määrityksellä.
Milloin Käyttää Mitäkin?
Paras lähestymistapa riippuu erityistarpeistasi ja prioriteeteistasi. Tässä on opas, joka auttaa sinua valitsemaan:
- Käytä Enumeita Kun:
- Tarvitset yksinkertaisen joukon numeerisia vakioita implisiittisellä kasvatuksella.
- Tarvitset käänteisen mäppäyksen (vaikka tämä on harvoin tarpeellista).
- Työskentelet vanhan koodin kanssa, joka jo käyttää enumeita laajasti, eikä sinulla ole kiireellistä tarvetta muuttaa sitä.
- Käytä Const Assertions -ominaisuutta Kun:
- Tarvitset joukon merkkijono- tai numeerisia vakioita, joiden tulisi olla muuttumattomia.
- Tarvitset avain-arvo-suhteen ja haluat välttää suoritusaikaisen lisäkuorman.
- Tree-shaking ja paketin koko ovat tärkeitä huomioitavia asioita.
- Käytä Union Types -tyyppejä Kun:
- Tarvitset yksinkertaisen ja ytimekkään tavan määrittää joukko sallittuja arvoja.
- Et tarvitse avain-arvo-suhdetta.
- Suorituskyky ja paketin koko ovat kriittisiä.
Esimerkkiskenaario: Käyttäjäroolien Määrittäminen
Tarkastellaan skenaariota, jossa sinun on määritettävä käyttäjäroolit sovelluksessa. Sinulla voi olla rooleja, kuten "Admin", "Editor" ja "Viewer".
Käyttämällä Enumeita:
enum UserRole {
Admin,
Editor,
Viewer,
}
function authorize(role: UserRole) {
// ...
}
Käyttämällä Const Assertions -ominaisuutta:
const UserRole = {
Admin: 'admin',
Editor: 'editor',
Viewer: 'viewer',
} as const;
type UserRoleType = typeof UserRole[keyof typeof UserRole];
function authorize(role: UserRoleType) {
// ...
}
Käyttämällä Union Types -tyyppejä:
type UserRole = 'admin' | 'editor' | 'viewer';
function authorize(role: UserRole) {
// ...
}
Tässä skenaariossa union types -tyypit tarjoavat ytimekkäimmän ja tehokkaimman ratkaisun. Const assertions ovat hyvä vaihtoehto, jos pidät avain-arvo-suhteesta, ehkä kunkin roolin kuvausten etsimiseen. Enumeita ei yleensä suositella tässä, ellei sinulla ole erityistä tarvetta numeerisille arvoille tai käänteiselle mäppäykselle.
Esimerkkiskenaario: API-päätepisteiden Tilakoodien Määrittäminen
Tarkastellaan skenaariota, jossa sinun on määritettävä API-päätepisteiden tilakoodit. Sinulla voi olla koodeja, kuten 200 (OK), 400 (Bad Request), 401 (Unauthorized) ja 500 (Internal Server Error).
Käyttämällä Enumeita:
enum StatusCode {
OK = 200,
BadRequest = 400,
Unauthorized = 401,
InternalServerError = 500
}
function processStatus(code: StatusCode) {
// ...
}
Käyttämällä Const Assertions -ominaisuutta:
const StatusCode = {
OK: 200,
BadRequest: 400,
Unauthorized: 401,
InternalServerError: 500
} as const;
type StatusCodeType = typeof StatusCode[keyof typeof StatusCode];
function processStatus(code: StatusCodeType) {
// ...
}
Käyttämällä Union Types -tyyppejä:
type StatusCode = 200 | 400 | 401 | 500;
function processStatus(code: StatusCode) {
// ...
}
Jälleen kerran, union types -tyypit tarjoavat ytimekkäimmän ja tehokkaimman ratkaisun. Const assertions ovat vahva vaihtoehto ja niitä voidaan pitää parempana, koska ne antavat selkeämmän kuvauksen tietylle tilakoodille. Enumit voivat olla hyödyllisiä, jos ulkoiset kirjastot tai API:t odottavat kokonaislukupohjaisia tilakoodeja ja haluat varmistaa saumattoman integraation. Numeeriset arvot vastaavat standardeja HTTP-koodeja, mikä voi yksinkertaistaa vuorovaikutusta olemassa olevien järjestelmien kanssa.
Suorituskykyyn Liittyvät Huomiot
Useimmissa tapauksissa suorituskykyero enumien, const assertions -ominaisuuden ja union types -tyyppien välillä on merkityksetön. Suorituskyvyn kannalta kriittisissä sovelluksissa on kuitenkin tärkeää olla tietoinen mahdollisista eroista.
- Enumit: Enumit aiheuttavat suoritusaikaista lisäkuormaa JavaScript-objektien luomisen vuoksi. Tämä lisäkuorma voi olla merkittävä suurissa sovelluksissa, joissa on monia enumeita.
- Const Assertions: Const assertions -ominaisuudella ei ole suoritusaikaista lisäkuormaa. Ne ovat yksinkertaisia JavaScript-objekteja, joita TypeScript käsittelee vain luku -tilassa.
- Union Types: Union types -tyypeillä ei ole suoritusaikaista lisäkuormaa. Ne ovat olemassa vain käännösaikana ja poistetaan käännöksen aikana.
Jos suorituskyky on suuri huolenaihe, union types -tyypit ovat yleensä paras valinta. Const assertions ovat myös hyvä vaihtoehto, erityisesti jos tarvitset avain-arvo-suhteen. Vältä enumien käyttöä koodin suorituskyvyn kannalta kriittisissä osissa, ellei sinulla ole siihen erityistä syytä.
Globaalit Vaikutukset ja Parhaat Käytännöt
Kun työskennellään projekteissa, joissa on kansainvälisiä tiimejä tai globaaleja käyttäjiä, lokalisointi ja kansainvälistäminen on erittäin tärkeää ottaa huomioon. Tässä on joitain parhaita käytäntöjä enumien ja niiden vaihtoehtojen käyttämiseen globaalissa kontekstissa:
- Käytä kuvaavia nimiä: Valitse enumin jäsenten nimet (tai const assertion avaimet), jotka ovat selkeitä ja yksiselitteisiä, jopa muille kuin natiiveille englannin puhujille. Vältä slangia tai ammattikieltä.
- Harkitse lokalisointia: Jos sinun on näytettävä enumin jäsenten nimiä käyttäjille, harkitse lokalisointikirjaston käyttöä, joka tarjoaa käännöksiä eri kielille. Esimerkiksi sen sijaan, että näyttäisit suoraan
Status.InProgress, voisit näyttääi18n.t('status.in_progress'). - Vältä kulttuurispesifisiä oletuksia: Ole tietoinen kulttuurieroista, kun määrität enumin arvoja. Esimerkiksi päivämäärämuodot, valuuttasymbolit ja mittayksiköt voivat vaihdella merkittävästi eri kulttuureissa. Jos sinun on esitettävä nämä arvot, harkitse kirjaston käyttöä, joka käsittelee lokalisointia ja kansainvälistämistä.
- Dokumentoi koodisi: Tarjoa selkeä ja ytimekäs dokumentaatio enumeillesi ja niiden vaihtoehdoille, selittäen niiden tarkoituksen ja käytön. Tämä auttaa muita kehittäjiä ymmärtämään koodiasi heidän taustastaan tai kokemuksestaan riippumatta.
Esimerkki: Käyttäjäroolien Lokalisointi
Palataan käyttäjäroolien esimerkkiin ja tarkastellaan, miten roolinimet voidaan lokalisoida eri kielille.
// Käyttämällä Const Assertions -ominaisuutta Lokalisoinnilla
const UserRole = {
Admin: 'admin',
Editor: 'editor',
Viewer: 'viewer',
} as const;
type UserRoleType = typeof UserRole[keyof typeof UserRole];
// Lokalisointifunktio (käyttäen hypoteettista i18n-kirjastoa)
function getLocalizedRoleName(role: UserRoleType, locale: string): string {
switch (role) {
case UserRole.Admin:
return i18n.t('user_role.admin', { locale });
case UserRole.Editor:
return i18n.t('user_role.editor', { locale });
case UserRole.Viewer:
return i18n.t('user_role.viewer', { locale });
default:
return 'Tuntematon rooli';
}
}
// Esimerkkikäyttö
const currentRole: UserRoleType = UserRole.Editor;
const localizedRoleName = getLocalizedRoleName(currentRole, 'fr-CA'); // Palauttaa lokalisoidun "Éditeur" kanadanranskaksi.
console.log(`Nykyinen rooli: ${localizedRoleName}`);
Tässä esimerkissä käytämme lokalisointifunktiota hakemaan käännetyn roolinimen käyttäjän kieliasetusten perusteella. Tämä varmistaa, että roolinimet näytetään käyttäjän ensisijaisella kielellä.
Johtopäätös
TypeScript enumit ovat hyödyllinen ominaisuus, mutta ne eivät ole aina paras valinta. Const assertions ja union types tarjoavat toteuttamiskelpoisia vaihtoehtoja, jotka voivat tarjota paremman suorituskyvyn, muuttumattomuuden ja koodin ylläpidettävyyden. Ymmärtämällä kunkin lähestymistavan edut ja haitat voit tehdä tietoon perustuvia päätöksiä siitä, mitä niistä käytät projekteissasi. Harkitse sovelluksesi erityistarpeita, tiimisi mieltymyksiä ja koodisi pitkäaikaista ylläpidettävyyttä. Punnnitsemalla näitä tekijöitä huolellisesti voit valita parhaan lähestymistavan vakioiden määrittämiseen TypeScript-projekteissasi, mikä johtaa puhtaampiin, tehokkaampiin ja paremmin ylläpidettäviin koodikantoihin.